/*
 * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3
 * http://www.gnu.org/licenses/gpl-3.0.html
 */

#ifndef PARSER_H
#define PARSER_H

#include <wx/arrstr.h>
#include <wx/event.h>
#include <wx/file.h>
#include <wx/filefn.h> // wxPathList
#include <wx/imaglist.h>
#include <wx/string.h>
#include <wx/thread.h>
#include <wx/timer.h>
#include <wx/treectrl.h>

#include <cbthreadpool.h>
#include <sdk_events.h>

#include "parserthread.h"
#include "parser_base.h"

#define PARSER_IMG_NONE                        -2
#define PARSER_IMG_CLASS_FOLDER                 0
#define PARSER_IMG_CLASS                        1
#define PARSER_IMG_CLASS_PRIVATE                2
#define PARSER_IMG_CLASS_PROTECTED              3
#define PARSER_IMG_CLASS_PUBLIC                 4
#define PARSER_IMG_CTOR_PRIVATE                 5
#define PARSER_IMG_CTOR_PROTECTED               6
#define PARSER_IMG_CTOR_PUBLIC                  7
#define PARSER_IMG_DTOR_PRIVATE                 8
#define PARSER_IMG_DTOR_PROTECTED               9
#define PARSER_IMG_DTOR_PUBLIC                  10
#define PARSER_IMG_FUNC_PRIVATE                 11
#define PARSER_IMG_FUNC_PROTECTED               12
#define PARSER_IMG_FUNC_PUBLIC                  13
#define PARSER_IMG_VAR_PRIVATE                  14
#define PARSER_IMG_VAR_PROTECTED                15
#define PARSER_IMG_VAR_PUBLIC                   16
#define PARSER_IMG_MACRO_DEF                    17
#define PARSER_IMG_ENUM                         18
#define PARSER_IMG_ENUM_PRIVATE                 19
#define PARSER_IMG_ENUM_PROTECTED               20
#define PARSER_IMG_ENUM_PUBLIC                  21
#define PARSER_IMG_ENUMERATOR                   22
#define PARSER_IMG_NAMESPACE                    23
#define PARSER_IMG_TYPEDEF                      24
#define PARSER_IMG_TYPEDEF_PRIVATE              25
#define PARSER_IMG_TYPEDEF_PROTECTED            26
#define PARSER_IMG_TYPEDEF_PUBLIC               27
#define PARSER_IMG_SYMBOLS_FOLDER               28
#define PARSER_IMG_VARS_FOLDER                  29
#define PARSER_IMG_FUNCS_FOLDER                 30
#define PARSER_IMG_ENUMS_FOLDER                 31
#define PARSER_IMG_MACRO_DEF_FOLDER             32
#define PARSER_IMG_OTHERS_FOLDER                33
#define PARSER_IMG_TYPEDEF_FOLDER               34
#define PARSER_IMG_MACRO_USE                    35
#define PARSER_IMG_MACRO_USE_PRIVATE            36
#define PARSER_IMG_MACRO_USE_PROTECTED          37
#define PARSER_IMG_MACRO_USE_PUBLIC             38
#define PARSER_IMG_MACRO_USE_FOLDER             39

#define PARSER_IMG_MIN PARSER_IMG_CLASS_FOLDER
#define PARSER_IMG_MAX PARSER_IMG_MACRO_USE_FOLDER

/**
 * Tree data associate with the symbol tree item
 * 与符号树项关联的树数据
 */
class ClassTreeData : public wxTreeItemData
{
public:
    ClassTreeData(Token* token)   { m_Token = token; }
    Token* GetToken()             { return m_Token;  }
    void   SetToken(Token* token) { m_Token = token; }
private:
    Token* m_Token;
};

class ClassBrowser;

namespace ParserCommon
{
    extern int idParserStart;
    extern int idParserEnd;
    /*分析器状态*/
    enum ParserState
    {
        /**
         * the Parser object is newly created, and we are parsing the predefined macro buffer, the
         * source files, and finally mark the project's tokens as local
         * 解释器(Parser)对象是新创建的,我们正在解析预定义的宏缓冲区/源文件,最后将项目的标记标记为本地(local)
         * [新建态]
         */
        ptCreateParser    = 1,

        /**
         * some files are changed by the user, so we are parsing the changed files
         * 有些文件被用户更改,因此我们正在分析更改的文件
         * [重解释态]
         * */
        ptReparseFile     = 2,

        /**
         * the user has add some files to the cbproject, so we are parsing the new added files
         * 用户已经向cbproject添加了一些文件,因此我们正在分析新添加的文件
         * [递增解释态]
         * */
        ptAddFileToParser = 3,

        /** non of the above three status, this means our Parser has finish all the jobs, and it is
         * in idle mode
         * 不是以上三种状态,这意味着我们的解析器已经完成了所有的工作,并且处于空闲模式
         * [空闲态]
         */
        ptUndefined       = 4
    };
}

/**
* 实现功能: Parser class holds all the tokens of a C::B project
* Parser class contains the TokenTree which is a trie structure to record the token information.
* For details about trie, see http://en.wikipedia.org/wiki/Trie
* The parser class manages Parser threaded Tasks in a ThreadPool. A ParserThread object is
* associated with a single source file.
* Batch parse mode means we have a lot of files to be parsed, so a lot of ParserThreads were
* generated and added to the ThreadPool, and finally, the ParserThread was executed by ThreadPool.
*
* 实现功能: 解析器类保存C::B项目的所有标记
 * Parser类包含TokenTree,它是记录令牌信息的trie结构.
 * 有关trie的详细信息,请参阅http://en.wikipedia.org/wiki/Trie
 * parser类管理线程池中的解析器线程任务.
 * ParserThread对象与单个源文件关联.
 * 批处理解析模式意味着我们有很多文件需要解析,因此产生了很多ParserThreads并将其添加到ThreadPool中,最后,ParserThread由ThreadPool执行.
*
*/
class Parser : public ParserBase
{
    friend class ParserThreadedTask;

public:
    /**
     * constructor
     * 参数说明: parent which is actually a NativeParser object
     * 参数说明: project the C::B project associated with the current Parser
     *
     * 构造函数
     * 参数说明: parent 它实际上是一个本地解释器(NativeParser)对象
     * 参数说明: project 与当前解析器关联的C::B项目
     */
    Parser(wxEvtHandler* parent, cbProject* project);
    /**
     * destructor
     * 析构函数
     * */
    virtual ~Parser();

    /**
     * Add files to batch parse mode, internally. The files will be parsed sequentially.
     * 参数说明: filenames input files name array
     * 在内部将文件添加到批处理解析模式.文件将按顺序解析.
     * 参数说明: filenames 输入的文件名数组
     */
    virtual void AddBatchParse(const StringList& filenames);

    /**
     * Add one file to Batch mode Parsing, this is the bridge between the main thread and the
     * thread pool, after this function call, the file(Parserthread) will be run from the thread
     * pool.
     * 参数说明: filenames input file name
     *
     * 添加一个文件到批处理模式解析,这是主线程和线程池之间的桥梁,在这个函数调用之后,文件(Parserthread)将从线程池运行.
     * 参数说明: filenames 输入文件名
     *
     */
    virtual void AddParse(const wxString& filename);

    /**
     * set the predefined macro definition string was collected from the GCC command line,
     * this function adds the string to an internal m_PredefinedMacros, and switch the ParserState
     * 设置从GCC命令行收集的预定义宏定义字符串,此函数将字符串添加到内部m_PredefinedMacros中,并切换ParserState
     */
    virtual void AddPredefinedMacros(const wxString& defs);

    /**
     * clears the list of predefined macros after it has been parsed
     * 解析预定义宏后清除其列表
     * */
    virtual void ClearPredefinedMacros();

    /**
     * return the predefined macro definition string that has been collected
     * 返回已收集的预定义宏定义字符串
     * */
    virtual const wxString GetPredefinedMacros() const;

    /**
     * set the associated C::B project pointer. (only used by one parser for whole workspace)
     *  @return true if it can do the switch, other wise, return false, and print some debug logs.
     *  设置关联的C::B项目指针.(仅用于整个工作区的一个解析器)
     *  返回值: 如果可以切换,则返回false,并打印一些调试日志.
     */
    virtual bool UpdateParsingProject(cbProject* project);

    /**
     * Must add a locker before call all named ParseBufferXXX functions, ParseBuffer function will
     * directly run the parsing in the same thread as the caller. So, take care if the time is limited.
     * this function usually used to parse the function body to fetch the local variable information.
     * 在调用所有命名的ParseBufferXXX函数之前必须添加一个锁存器,ParseBuffer函数将直接在与调用方相同的线程中运行解析.
     * 所以,如果时间有限,一定要小心.
     * 此函数通常用于解析函数体以获取局部变量信息.
     */
    virtual bool ParseBuffer(const wxString& buffer, bool isLocal, bool bufferSkipBlocks = false,
                             bool isTemp = false, const wxString& filename = wxEmptyString,
                             int parentIdx = -1, int initLine = 0);

    /**
     * parser the current editor control, this function is used to list all the functions in the
     * current code editor
     * 解析器当前编辑器控件,此函数用于列出当前代码编辑器中的所有函数
     */
    virtual bool ParseBufferForFunctions(const wxString& buffer);

    /**
     * parse the buffer for collecting exposed namespace scopes
     * 分析缓冲区以收集公开的命名空间作用域
     * */
    virtual bool ParseBufferForNamespaces(const wxString& buffer, NameSpaceVec& result);

    /**
     * parse the buffer for collecting using namespace directive
     * 为收集using namespace指令解释缓冲区
     * */
    virtual bool ParseBufferForUsingNamespace(const wxString& buffer, wxArrayString& result, bool bufferSkipBlocks = true);

    /**
     * mark this file to be re-parsed in the TokenTree, tick the reparse timer, note it looks like
     * the isLocal parameter is not used in Parser::Reparse function.
     * A better function name could be: MarkFileNeedToBeReParsed()
     *
     * 在标记树中标记要重新分析的文件,勾选重新分析计时器,注意,在Parser::reparse函数中似乎没有使用isLocal参数.
     * 更好的函数名可以是:MarkFileNeedToBeReParsed()
     *
     */
    virtual bool Reparse(const wxString& filename, bool isLocal = true);

    /**
     * this usually happens when user adds some files to an existing project, it just use AddParse()
     * function internally to add the file. and switch the ParserState to ParserCommon::ptAddFileToParser.
     * 这通常发生在用户向现有项目添加一些文件时,它只是在内部使用AddParse()函数添加文件.
     * 并将ParserState切换到ParserCommon::ptAddFileToParser.
     */
    virtual bool AddFile(const wxString& filename, cbProject* project, bool isLocal = true);

    /**
     * this usually happens when the user removes a file from the existing project, it will remove
     * all the tokens belong to the file.
     * 这通常发生在用户从现有项目中删除文件时,它将删除属于该文件的所有标记.
     */
    virtual bool RemoveFile(const wxString& filename);

    /**
     * check to see a file is parsed already, it first check the TokenTree to see whether it has
     * the specified file, but if a file is already queued (put in m_BatchParseFiles), we regard it
     * as already parsed.
     * 检查一个文件是否已经被解析,它首先检查令牌树是否有指定的文件,但是如果一个文件已经排队(放入m_BatchParseFiles中),我们将其视为已经解析.
     */
    virtual bool IsFileParsed(const wxString& filename);

    /**
     * check to see whether Parser is in Idle mode, there is no work need to be done in the Parser
     * 检查解析器是否处于空闲模式,解析器中不需要做任何工作
     * */
    virtual bool     Done();

    /**
     * if the Parser is not in Idle mode, show which need to be done
     * 如果解析器未处于空闲模式,则显示需要执行的操作
     * */
    virtual wxString NotDoneReason();

protected:
    // used for measuring the batch parsing time
    // 用于测量批量解析时间
    void StartStopWatch();
    // used for measuring the batch parsing time
    void EndStopWatch();

    /**
     * Node: Currently, the max. concurrent ParserThread number should be ONE, CC does not support
     * multiply threads parsing.
     * 节点：当前,最大.
     * 并发解析器线程数应为1,CC不支持多线程分析.
     */
    unsigned int GetMaxThreads() const { return m_Pool.GetConcurrentThreads(); }

    /**
     * Not used, because the ThreadPool only support running ONE ParserThread concurrently
     * 未使用,因为线程池只支持并发运行一个ParserThread
     * */
    void SetMaxThreads(unsigned int max) { m_Pool.SetConcurrentThreads(max); }

    /**
     * parse the file, either immediately or delayed.
     * 参数说明: isLocal true if the file belong to a C::B project
     * 参数说明: locked give the status of the Tokentree, false means the tree is not locked
     *
     * 立即或延迟解析文件.
     * 参数说明: isLocal 如果文件属于C::B项目,则为true
     * 参数说明: locked 给出令牌树的状态,false表示树未被锁定
     */
    bool Parse(const wxString& filename, bool isLocal = true, bool locked = false);

    /**
     * delete those files from the TokenTree, and add them again through AddParse() function
     * 从令牌树中删除这些文件,然后通过AddParse()函数再次添加它们
     * */
    void ReparseModifiedFiles();

    /**
     * cancel all the tasks in the thread pool m_Pool
     * 取消线程池m_Pool中的所有任务
     * */
    void TerminateAllThreads();

    /**
     * When a ThreadPool batch parse stage is done, it will issue a cbEVT_THREADTASK_ALLDONE message.
     * In some situations this event will be triggered, such as:
     * - batch parsing for cpp source files
     * - mark tokens belong to the cb project as local tokens
     *
     * 当线程池批处理分析阶段完成时,它将发出cbEVT_THREADTASK_ALLDONE消息.
     * 在某些情况下,会触发此事件,例如：
     * -cpp源文件的批处理分析
     * -将属于cb项目的令牌标记为本地令牌
     *
     */
    void OnAllThreadsDone(CodeBlocksEvent& event);

    /**
     * some files in the Tokentree is marked as need to be reparsed, this can be done by a call
     * of Reparse() before. So, in this timer event handler, we need to remove all the tokens of
     * files in the Tree, and then re-parse them again. This is done by AddParse() again. the Parser
     * status now switch to ParserCommon::ptReparseFile.
     *
     * 令牌树中的某些文件被标记为需要重新分析,这可以通过调用Reparse()来完成.
     * 因此,在这个计时器事件处理程序中,我们需要删除树中文件的所有标记,然后重新解析它们.
     * 这是由AddParse()再次完成的.
     * 解析器状态现在切换到ParserCommon::ptReparseFile.
     */
    void OnReparseTimer(wxTimerEvent& event);

    /**
     * A timer is used to optimized the event handling for parsing, e.g. several files/projects
     * were added to the project, so we don't start the real parsing stage until the last
     * file/project was added,
     *
     * 计时器用于优化解析的事件处理,
     * 例如在项目中添加了多个文件/项目,
     * 因此在添加最后一个文件/项目之前,我们不会启动真正的解析阶段,
     */
    void OnBatchTimer(wxTimerEvent& event);

    /**
     * The parser will let its parent (NativeParser) to handle the event, as the CodeCompletion instance
     * was set as the next handler of the NativeParser. Those events can finally go to the CodeCompletion's
     * event handler.
     * 参数说明: state the state of the Parser, it could be any kind of enum ParserState
     * 参数说明: id either idParserStart or idParserEnd
     * 参数说明: info the log message
     *
     * 解析器将让其父级(NativeParser)处理事件,因为CodeCompletion实例被设置为NativeParser的下一个处理程序.
     * 这些事件最终可以转到CodeCompletion的事件处理程序.
     * 参数说明: state 解析器的状态,它可以是任何类型的enum ParserState
     * 参数说明: id idParserStart或idParserEnd
     * 参数说明: info 日志消息
     */
    void ProcessParserEvent(ParserCommon::ParserState state, int id, const wxString& info = wxEmptyString);

    /**
     * read Parser options from configure file
     * 从配置文件中读取解释器选项
     * */
    virtual void            ReadOptions();
    /**
     * write Parse options to configure file
     * 向配置文件中写入解释器选项
     * */
    virtual void            WriteOptions();

private:
    /**
     * the only usage of this function is in the Parserthread class, when handling include directives
     * the parserthread use some call like m_Parent->ParseFile() to call this function, but this function
     * just call Parser::Parse() function, which either run the syntax analysis immediately or create
     * a parsing task in the Pool.
     * 参数说明: filename the file we want to parse
     * 参数说明: isGlobal true if the file is not belong to a C::B project
     * 参数说明: locked true if the TokenTree is locked. when initially parse a translation unit file
     * the locked should be set as false, but if you want to recursive parse to an include file
     * the locked value should be set as true.
     *
     * 这个函数的唯一用法是在Parserthread类中,
     * 当处理include指令时,Parserthread使用一些类似m_Parent->ParseFile()的调用来调用这个函数,
     * 但是这个函数只调用Parser::Parse()函数,它要么立即运行语法分析,要么在池中创建一个解析任务.
     * 参数说明: filename 我们要解析的文件
     * 参数说明: isGlobal 如果文件不属于C::B项目,则为true
     * 参数说明: locked 如果令牌树被锁定,则为true.
     * 最初解析翻译单元文件时locked应该设置为false,
     * 但是如果您希望递归解析到include文件,锁定值应设置为true.
     */
    virtual bool ParseFile(const wxString& filename, bool isGlobal, bool locked = false);

    /**
     * connect event handlers of the timers and thread pool
     * 连接计时器和线程池的事件处理程序
     * */
    void ConnectEvents();

    /**
     * Disconnect event handlers of the timers and thread pool
     * 断开计时器和线程池的事件处理程序
     * */
    void DisconnectEvents();

    /**
     * when initialized, this variable will be an instance of a NativeParser
     * 初始化时,此变量将是NativeParser的实例
     * */
    wxEvtHandler*             m_Parent;

    /**
     * referring to the C::B cbp project currently parsing in one parser per workspace mode
     * 引用当前在每个工作区模式下使用一个解析器进行解析的C::B cbp项目
     * */
    cbProject*                m_Project;

protected:
    /**
     * used to detect changes between in-memory data and cache, true if loaded from cache
     * 用于检测内存中数据和缓存之间的更改,如果从缓存加载,则为true
     * */
    bool                      m_UsingCache;

    /**
     * Thread Pool, executing all the ParserThread, used in batch parse mode. The thread pool can
     * add/remove/execute the ParserThread tasks, it will also notify the Parser that all the thread
     * are done.
     * 线程池,执行所有ParserThread,在批处理解析模式下使用.
     * 线程池可以添加/删除/执行ParserThread任务,它还将通知解析器所有线程都已完成.
     */
    cbThreadPool              m_Pool;

    /**
     * true, if the parser is still busy with parsing, false if the parsing stage has finished
     * this value is set in parserthreadedtask after putting all the batchFiles to pool(task)
     * it was reset after the last stage (mark tokens as local)
     * 如果解析器仍忙于解析,则为true,如果解析阶段已完成,则为false.
     * 在将所有批处理文件放入池(任务)后,在parserthreadedtask中设置此值,则在最后一个阶段之后重置(将标记标记为本地)
     */
    bool                      m_IsParsing;


    /**
     * Indicates some files in the current project need to be re-parsed, this is commonly caused
      * that the "real-time parsing option" is enabled, and user is editing source file.
      * 表示当前项目中的某些文件需要重新分析,这通常是因为启用了“实时解析选项”,而用户正在编辑源文件.
      */
    bool                      m_NeedsReparse;

    /**
     * batch Parse mode flag. It was set after consuming m_PredefinedMacros, it was reset after the
     * final stage (mark token as local).
     * 批处理分析模式标志.
     * 它是在消费m_PredefinedMacros之后设置的,在最后阶段之后被重置(标记令牌[标识符]为本地[local]).
     */
    bool                      m_IsFirstBatch;

private:

    /**
     * a file is need to be reparsed, maybe another file will to be reparsed very soon, so use
     * a timer to collect all the files need to be reparsed. This avoid starting running the thread
     * pool to quickly
     *
     * 一个文件需要重新解析,也许另一个文件很快就会被重新解析,所以使用计时器来收集所有需要重新解析的文件.
     * 这样可以避免快速启动线程池
     */
    wxTimer                   m_ReparseTimer;

    /**
     * a timer to delay the operation of batch parsing, see OnBatchTimer() member function as a
     * reference
     * 一个延迟批处理解析操作的计时器,请参阅OnBatchTimer()成员函数作为参考
     */
    wxTimer                   m_BatchTimer;

    /**
     * a stop watch to measure parsing time
     * 用来测量解析时间的秒表
     * */
    wxStopWatch               m_StopWatch;
    bool                      m_StopWatchRunning;
    long                      m_LastStopWatchTime;

    /**
     * Parser::OnAllThreadsDone will be called when m_Pool finished its job, but when we run a
     * batch parsing, we may receive several such event from the m_Pool, because
     * 1, when ParserThreadedTask finished
     * 2, when batchFiles get finished
     * 3, mark C::B project files's token as local
     *
     * 当m_Pool完成任务时,将调用Parser::OnAllThreadsDone,
     * 但是当我们运行批处理解析时,我们可能会从m_Pool接收到几个这样的事件,因为:
     * 1, 当ParserThreadedTask完成时
     * 2, 当batchFiles(批处理文件)完成时
     * 3, 将C::B项目文件的标记标记为本地
     */
    bool                      m_IgnoreThreadEvents;

    /**
     * All other batch parse files, like the normal headers/sources
     * 所有其他批处理解析文件,如普通的头/源文件
     * */
    StringList                m_BatchParseFiles;

    /**
     * Pre-defined macros, its a buffer queried from the compiler command line
     * 预定义的宏,它是从编译器命令行查询的缓冲区
     * */
    wxString                  m_PredefinedMacros;
    // for debugging
    // 用于调试
    wxString                  m_LastPredefinedMacros;

    /**
     * used to measure batch parse time
     * 用于测量批处理分析时间
     * */
    bool                      m_IsBatchParseDone;

    /**
     * indicated the current state the parser
     * 指示分析器的当前状态
     * */
    ParserCommon::ParserState m_ParserState;

    /**
     * if true, all the files of the current project will be labeled as "local"
     * 如果为true,则当前项目的所有文件都将标记为“本地”
     * */
    bool                      m_NeedMarkFileAsLocal;

    /**
     * A list to contain pointers to internal running threads
     * 包含指向内部运行线程的指针的列表
     * */
    typedef std::list<cbThreadedTask*> TasksQueue;
    TasksQueue                m_tasksQueue;

    /**
     * Remember a newly created internal running threads
     * 还记得一个新创建的内部运行线程吗
     * */
    void AddParserThread(cbThreadedTask* task);

    /**
     * Remove a completed internal running threads
     * 删除已完成的内部运行线程
     * */
    void RemoveParserThread(cbThreadedTask* task);

    /**
     * Tell internal running threads to abort further processing
     * 告诉内部正在运行的线程中止进一步的处理
     *
     * */
    void AbortParserThreads();
};

#endif // PARSER_H
